#pragma once
#include "Socket.hpp"
#include "InetAddr.hpp"
#include<functional>
#include <memory>
#include <signal.h>

using callback_t =std::function<std::string(std::string&)>;

class TcpServer
{
public:
    TcpServer(int port,callback_t cb)
        : _port(port),
          _listensocket(std::make_unique<TcpSocket>()),
          _cb(cb)
    {
        _listensocket->BuildlistenSocketMethod(_port);
    }

    void HandleRequest(std::shared_ptr<Socket> sockfd, InetAddr addr)
    {
        // 长服务
        std::string inbuffer;
        while (true)
        {
            ssize_t n = sockfd->Recv(&inbuffer);
            if (n > 0)
            {
                // 都必须和协议有关！！！
                // 1. 你怎么知道inbuffer里面有至少一个完整的报文呢？
                // 2. 如何把这个完整的报文，交给上层呢？
                // 3. 上层拿到了一个报文，该如何处理呢？？
                LOG(Loglevel::DEBUG) << addr.ToString() << "# " << inbuffer;
                
                std::string send_str = _cb(inbuffer);
                if(send_str.empty())
                    continue;
                sockfd->Send(send_str);
            }
            else if (n == 0)
            {
                LOG(Loglevel::DEBUG) << addr.ToString() << " quit, me too!";
                break;
            }
            else
            {
                LOG(Loglevel::DEBUG) << addr.ToString() << " read error, quit!";
                break;
            }
        }
        sockfd->Close();
    }

    void Run()
    {
        signal(SIGCHLD,SIG_IGN);
        while (true)
        {
            InetAddr addr;
            auto sockfd = _listensocket->Accept(&addr);
            if(!sockfd)
                continue;
            LOG(Loglevel::INFO)<<"获得一个新链接："<<addr.ToString()
            << ",sockfd: "<<sockfd->SockFd();

            if(fork()==0)
            {
                _listensocket->Close();
                HandleRequest(sockfd,addr);
                exit(0);
            }
            sockfd->Close();
        }
    }

    ~TcpServer()
    {}
private:
    int _port;
    std::unique_ptr<Socket> _listensocket;
    callback_t _cb;
};